/*
 ============================================================================
 Name        : server-client-in-c.c
 Author      : Krzysztof Kardasz
 Version     :
 Copyright   : Krzysztof Kardasz
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
#include <sys/unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <syslog.h>
#include <signal.h>
#include <sys/wait.h>

#define DAEMON_NAME "NetworkDaemon"

struct hostent * server;

void conn ();
void srv ();

int main()
{
    pid_t pid, sid;
    pid = fork();
    if (pid < 0) {
        return 1;
    }
    if (pid > 0) {
        return 0;
    }

    sid = setsid();
    if (sid < 0) {
        fprintf(stderr, "Cannot create a new SID for the child process\n");
        return 1;
    }

    char hostname[] = "localhost";
    server = gethostbyname(hostname);
    if (server == NULL) {
        printf("ERROR, no such host");
        return 1;
    }

    if ((chdir("/")) < 0) {
        fprintf(stderr, "Change the current working directory '/'\n");
        return 1;
    }

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    srv();

    return EXIT_SUCCESS;
}

void conn ()
{
    int sockfd;
    struct sockaddr_in serv_addr;
    int port = 8080;

    sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sockfd < 0) {
        syslog(LOG_INFO, "%s: ERROR opening socket", DAEMON_NAME);
    }
    memcpy(&serv_addr.sin_addr, server->h_addr_list[0], server->h_length);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);

    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))) {
        syslog(LOG_INFO, "%s: ERROR connectiong", DAEMON_NAME);
    }
    syslog(LOG_INFO, "%s: Connected ok", DAEMON_NAME);
}


void srv ()
{
    int srv_fd;
    struct sockaddr_in address;
    int addrlen;
    int new_fd;


    srv_fd = socket(AF_INET,SOCK_STREAM, 0);
    if (srv_fd) {
        syslog(LOG_INFO, "%s: ERROR when creating socket", DAEMON_NAME);
        return;
    }

    address.sin_family      = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port        = htons(11223);

    if (bind(srv_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
        syslog(LOG_INFO, "%s: ERROR when binding", DAEMON_NAME);
        return;
    }

    if (listen(srv_fd, 2) < 0) {
        syslog(LOG_INFO, "%s: ERROR when listen", DAEMON_NAME);
        return;
    }


    addrlen = sizeof(address);

    while(1) {
        if ((new_fd = accept(srv_fd, (struct sockaddr *) &address, &addrlen)) < 0) {
            syslog(LOG_INFO, "%s: ERROR when accepting connection", DAEMON_NAME);
            return;
        }

        syslog(LOG_INFO, "%s: Connection accepted", DAEMON_NAME);

        if (fork() == 0) {
            conn ();
            conn ();
            conn ();
            sleep(30);
            close(new_fd);

            exit(0);
        } else {
            close(new_fd);
        }
    }
    close(srv_fd);
}
